﻿#pragma once
#include "XyNet/Global.h"

namespace XyNet
{
	/// 过程计时器
	template <typename T>
	class SharedObject : noncopyable
	{
	public:
		//////////////////////////////////////////////////////////////////////////

		class SharedLock : noncopyable
		{
		public:
			SharedLock(const SharedObject<T>* object) : _object(object), _lock(object->_mutex) {}

			inline void unlock() { _lock.unlock(); }

			inline const T* getObject() { return &_object->_object; }

		private:
			const SharedObject<T>* _object;
			shared_lock<shared_mutex> _lock;
		};

		//////////////////////////////////////////////////////////////////////////

		class UpgradeLock : noncopyable
		{
		public:
			UpgradeLock(SharedObject<T>* object) : _object(object), _lock(object->_mutex) {}

			~UpgradeLock()
			{
				if (_uniqueLock)
					_uniqueLock.reset();
			}

			inline void unlock()
			{
				if (_uniqueLock)
					_uniqueLock.reset();
				_lock.unlock();
			}

			inline T* toUnique()
			{
				assert(!_uniqueLock);
				_uniqueLock = make_unique<upgrade_to_unique_lock<shared_mutex>>(_lock);
				return &_object->_object;
			}

			inline const T* toUpgrade()
			{
				assert(_uniqueLock);
				_uniqueLock.reset();
				return &_object->_object;
			}

			inline const T* getObject() { return &_object->_object; }

		private:
			SharedObject<T>* _object;
			upgrade_lock<shared_mutex> _lock;
			unique_ptr<upgrade_to_unique_lock<shared_mutex>> _uniqueLock;
		};

		//////////////////////////////////////////////////////////////////////////

		class UniqueLock : noncopyable
		{
		public:
			UniqueLock(SharedObject<T>* object) : _object(object), _lock(object->_mutex) {}

			inline void unlock() { _lock.unlock(); }

			inline T* getObject() { return &_object->_object; }

		private:
			SharedObject<T>* _object;
			unique_lock<shared_mutex> _lock;
		};

		//////////////////////////////////////////////////////////////////////////

		SharedObject() {}
		SharedObject(const T& object) : _object(object) {}

		inline shared_ptr<SharedLock> createSharedLock() const
		{
			return make_shared<SharedLock>(this);
		}

		inline shared_ptr<UpgradeLock> createUpgradeLock()
		{
			return make_shared<UpgradeLock>(this);
		}

		inline shared_ptr<UniqueLock> createUniqueLock()
		{
			return make_shared<UniqueLock>(this);
		}

	private:
		T _object;
		mutable shared_mutex _mutex;
	};
}